#include "lua.h"
#include "lauxlib.h"
#include "cm_modem_info.h"
#include "cm_virt_at.h"
#include "lua_test_entry.h" // For lua_event_post
#include <string.h>
#include <stdlib.h>

int net_urc_ref = LUA_NOREF; // Remove 'static' to make it global
static lua_State *gL = NULL; // Global Lua state for URC callback

// Lua: quality_table = net.get_signal_quality()
static int l_net_get_signal_quality(lua_State *L) {
    cm_radio_info_t radio_info;
    int32_t ret = cm_modem_info_radio(&radio_info);

    if (ret == 0) {
        lua_newtable(L);

        // The SDK returns values scaled by 10, convert them to standard float values
        lua_pushstring(L, "rssi");
        lua_pushnumber(L, (double)((int16_t)(radio_info.rssi - 111) * 10) / 10.0);
        lua_settable(L, -3);

        lua_pushstring(L, "rsrp");
        lua_pushnumber(L, (double)((int16_t)(radio_info.rsrp - 140) * 10) / 10.0);
        lua_settable(L, -3);

        lua_pushstring(L, "rsrq");
        lua_pushnumber(L, (double)((int16_t)((5 * radio_info.rsrq - 195) > -30) ? -30 : (5 * radio_info.rsrq - 195)) / 10.0);
        lua_settable(L, -3);

    } else {
        lua_pushnil(L);
    }
    return 1;
}

// Lua: status_code = net.get_reg_status()
static int l_net_get_reg_status(lua_State *L) {
    uint8_t rsp[128] = {0};
    int32_t rsp_len = sizeof(rsp);
    int32_t ret = cm_virt_at_send_sync((uint8_t *)"AT+CEREG?\r\n", rsp, &rsp_len, 2000);

    if (ret == 0) {
        // Example response: +CEREG: 0,1
        char *p = strstr((char *)rsp, "+CEREG:");
        if (p) {
            int n, stat;
            if (sscanf(p, "+CEREG: %d,%d", &n, &stat) == 2) {
                lua_pushinteger(L, stat);
                return 1;
            }
        }
    }
    lua_pushnil(L);
    return 1;
}

static void net_urc_callback(uint8_t *urc, int32_t urc_len)
{
    if (gL == NULL || net_urc_ref == LUA_NOREF) return;

    // Example URC: +CEREG: 1
    char *p = strstr((char *)urc, "+CEREG:");
    if (p)
    {
        int stat;
        if (sscanf(p, "+CEREG: %d", &stat) == 1)
        {
            lua_event_t event;
            event.id = LUA_EVENT_NET_REG_STATUS;
            event.data.ival = stat;
            lua_event_post(&event);
        }
    }
}


// Lua: net.on_reg_change(callback_func)
static int l_net_on_reg_change(lua_State *L) {
    if (net_urc_ref != LUA_NOREF) {
        luaL_unref(L, LUA_REGISTRYINDEX, net_urc_ref);
        net_urc_ref = LUA_NOREF;
    }

    if (lua_isfunction(L, 1)) {
        net_urc_ref = luaL_ref(L, LUA_REGISTRYINDEX);
        cm_virt_at_urc_cb_reg((const uint8_t *)"+CEREG", net_urc_callback);
    } else {
        cm_virt_at_urc_cb_dereg((const uint8_t *)"+CEREG", net_urc_callback);
    }
    return 0;
}


static const luaL_Reg net_lib[] = {
    {"get_signal_quality", l_net_get_signal_quality},
    {"get_reg_status", l_net_get_reg_status},
    {"on_reg_change", l_net_on_reg_change},
    {NULL, NULL}
};

int luaopen_net(lua_State *L) {
    gL = L;
    luaL_newlib(L, net_lib);
    return 1;
}
